package com.hyz.yuaiagent.app;

import com.hyz.yuaiagent.advisor.MyLoggerAdvisor;
import com.hyz.yuaiagent.chatmemory.FileBasedChatMemory;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.QuestionAnswerAdvisor;
import org.springframework.ai.chat.client.advisor.api.Advisor;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;

import java.util.List;

import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY;
import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY;

@Slf4j
@Component
public class LoveApp {


    public static final String SysPrompt = "扮演深耕恋爱心理领域的专家。开场向用户表明身份，告知用户可倾诉恋爱难题。" +
            "围绕单身、恋爱、已婚三种状态提问：单身状态询问社交圈拓展及追求心仪对象的困扰；恋爱状态询问沟通、" +
            "习惯差异引发的矛盾；已婚状态询问家庭责任与亲属关系处理的问题。" +
            "引导用户详述事情经过、对方反应及自身想法，以便给出专属解决方案";
    private final ChatClient chatClient;
    private final VectorStore loveAppVectorStore;
    private final Advisor lovaAppCloudAdvisor;
    private final VectorStore pgVectorStore;


    /**
     * 构造函数用于初始化LoveApp对象
     *
     * @param dashscopeChatModel  聊天模型，用于创建聊天客户端
     * @param loveAppVectorStore  向量存储实例，用于存储和检索向量数据
     * @param loveAppCloudAdvisor 云顾问实例，提供云服务相关的建议
     *                            <p>
     *                            该构造函数通过@Autowired注解实现依赖注入，将所需的组件注入到LoveApp类中
     *                            它初始化了LoveApp对象的向量存储、云顾问和聊天客户端属性
     */
    @Autowired
    public LoveApp(ChatModel dashscopeChatModel,
                   @Qualifier("loveAppVectorStore") VectorStore loveAppVectorStore,
                   @Qualifier("loveAppCloudAdvisor") Advisor loveAppCloudAdvisor, VectorStore pgVectorStore) {
        this.loveAppVectorStore = loveAppVectorStore;
        this.lovaAppCloudAdvisor = loveAppCloudAdvisor;
        this.chatClient = getChatClient(dashscopeChatModel);
        this.pgVectorStore = pgVectorStore;
    }

    @NonNull
    private ChatClient getChatClient(ChatModel dashscopeChatModel) {
        final ChatClient chatClient;
        //通过ChatClinet Builder的方式进行初始化
//        InMemoryChatMemory chatMemory = new InMemoryChatMemory();
        FileBasedChatMemory chatMemory = new FileBasedChatMemory(System.getProperty("user.dir") + "/tmp");
        chatClient = ChatClient.builder(dashscopeChatModel)
                //1.初始化系统提示词
                .defaultSystem(SysPrompt)
                //2.初始化拦截器
                .defaultAdvisors(
                        //初始化一个 记忆拦截器
                        new MessageChatMemoryAdvisor(chatMemory),
                        //自定义日志拦截器
                        new MyLoggerAdvisor()
/*                        //让大模型读两边请求,可提高大型语言模型的推理能力
                        , new ReReadingAdvisor()*/
                )
                .build();
        return chatClient;
    }

    /**
     * 基础对话 支持多轮对话
     * 1.用我们初始化好的chatCLinet对象
     *
     * @param message
     * @param chatId
     * @return
     */
    public String doChat(String message, String chatId) {

        ChatResponse chatResponse = chatClient.prompt()
//                1. 用户提示词
                .user(message)
//                2. 拦截器参数
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
//                         来自上下文的聊天内存响应大小 如果为1 就是只能记忆1轮对话
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))
//                3.调用AI
                .call()
//                响应
                .chatResponse();

        String content = chatResponse.getResult().getOutput().getText();

        return content;
    }


    public Flux<String> doChatByStream(String message, String chatId) {

        Flux<String> content = chatClient.prompt()
//                1. 用户提示词
                .user(message)
//                2. 拦截器参数
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
//                         来自上下文的聊天内存响应大小 如果为1 就是只能记忆1轮对话
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))
//                3.调用AI
                .stream()
                .content();

        return content;
    }

    /**
     * 基础对话支持结构化输出
     *
     * @param message
     * @param chatId
     */

    public void doChatWithReport(String message, String chatId) {
        LoveRecode loveRecode = chatClient.prompt()
                .user(message)
                .system(SysPrompt + "每次对话以后都需要生成恋爱结果,标题为{用户名}的恋爱报告,内容为建议列表")
                .call()
                .entity(LoveRecode.class);

        log.info("恋爱报告: {}", loveRecode);


    }

    /**
     * 基于知识库的问答
     *
     * @param msg    用户的提问消息
     * @param chatID 聊天会话的唯一标识符
     */
    public void chatWithRAG(String msg, String chatID) {
        // 构建聊天请求并发送，获取聊天响应
        ChatResponse chatResponse = chatClient.prompt()
                // 设置用户输入的原始消息
                .user(msg)
                // 添加聊天顾问，用于配置聊天行为
                .advisors(
                        // 配置会话内存，使用CHAT_MEMORY_CONVERSATION_ID_KEY指定会话ID
                        spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatID)
                                // 配置聊天记忆的检索大小，这里设置为10轮对话记忆
                                .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10)
                )
                // 添加问题回答顾问，结合向量存储（知识库）进行问答 !!!!!!!!!!!!
                .advisors(new QuestionAnswerAdvisor(loveAppVectorStore))
                // 添加自定义的日志记录顾问
                .advisors(new MyLoggerAdvisor())
                // 调用API，发送请求并获取响应
                .call()
                // 获取ChatResponse对象
                .chatResponse();

        // 提取并转换聊天响应中的文本答案
        String string = chatResponse.getResult().getOutput().getText().toString();
        // 日志输出答案
        log.info("答案{}:", string);
    }

    /**
     * 与云RAG（Retrieval-Augmented Generation）进行聊天
     * 该方法负责构建聊天请求，发送请求，并处理聊天响应
     *
     * @param msg    用户输入的消息，用于生成聊天请求
     * @param chatID 聊天会话的唯一标识符，用于关联聊天上下文
     */
    public void chatWithCloudRAG(String msg, String chatID) {
        // 使用chatClient创建一个聊天请求，并设置用户消息和顾问配置
        ChatResponse chatResponse = chatClient.prompt()
                // 设置用户提供的原始消息文本
                .user(msg)
                // 添加顾问以定制聊天行为，例如记忆和检索历史对话
                .advisors(
                        // 配置特定于当前聊天会话的记忆参数
                        spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatID) // 设置会话ID以跟踪聊天上下文
                                // 设置从聊天记忆中检索的历史对话数量
                                .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10) // 检索过去10轮对话作为上下文
                )
                // 添加LoveAppCloudAdvisor顾问，提供额外的聊天配置或行为!!!!!!!!!!!!!!!
                .advisors(lovaAppCloudAdvisor)
                // 添加自定义的日志记录顾问，用于记录聊天过程中的信息
                .advisors(new MyLoggerAdvisor())
                // 发送聊天请求并接收响应
                .call()
                // 获取ChatResponse对象，包含聊天结果
                .chatResponse();

        // 从chatResponse对象中提取聊天结果中的文本答案
        String string = chatResponse.getResult().getOutput().getText().toString();
        // 记录答案到日志中，方便后续分析或调试
        log.info("答案{}:", string);
    }

    /**
     * 基于pgsql的rag
     * 该方法通过chatClient发送用户消息，结合顾问配置，获取聊天响应，并记录结果
     *
     * @param msg    用户输入的消息文本
     * @param chatID 当前聊天会话的唯一标识符
     */
    public void chatWithLocalRAG(String msg, String chatID) {
        // 使用chatClient创建一个聊天请求，并设置用户消息和顾问配置
        ChatResponse chatResponse = chatClient.prompt()
                // 设置用户提供的原始消息文本
                .user(msg)
                // 添加顾问以定制聊天行为，例如记忆和检索历史对话
                .advisors(
                        // 配置特定于当前聊天会话的记忆参数
                        spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatID) // 设置会话ID以跟踪聊天上下文
                                // 设置从聊天记忆中检索的历史对话数量
                                .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10) // 检索过去10轮对话作为上下文
                )
                // 添加基于pgsql的rag知识库问答
                .advisors(new QuestionAnswerAdvisor(pgVectorStore))
                // 添加自定义的日志记录顾问，用于记录聊天过程中的信息
                .advisors(new MyLoggerAdvisor())
                // 发送聊天请求并接收响应
                .call()
                // 获取ChatResponse对象，包含聊天结果
                .chatResponse();

        // 从chatResponse对象中提取聊天结果中的文本答案
        String string = chatResponse.getResult().getOutput().getText().toString();
        // 记录答案到日志中，方便后续分析或调试
        log.info("答案{}:", string);
    }

    record LoveRecode(String title, List<String> context) {

    }

}
